import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

public class RunMe {

	public static void main(String[] args) {
		AlgorithmManager am = new AlgorithmManager();
		RelationHolder originalRelation = new RelationHolder(
				"Original Relation");
		RelationHolder rel3nf = new RelationHolder(
				"3NF - Lossless Decompositions and Dependency Preservation");
		RelationHolder relBCNF = new RelationHolder(
				"BCNF - Lossless Join Property Preserved");
		RelationHolder rel4nf = new RelationHolder(
				"4NF - Lossless Join Property Preserved");

		Scanner sc = new Scanner(System.in);

		beforeInputDialog();

		getInput(originalRelation, am, sc);

		afterInputDialog();

		int choice;
		do {
			choice = sc.nextInt();

			switch (choice) {
			case 1:
				if (!am.containsMVD(originalRelation.getRelation("Universal"))) {
					rel3nf = am.build3NF(originalRelation);
					rel3nf.printRelations();
					break;
				} else {
					System.out
							.println("Sorry, that relation has an MVD, you may only select 4NF (#3)");
					break;
				}
			case 2:
				if (!am.containsMVD(originalRelation.getRelation("Universal"))) {
					relBCNF = am.buildBCNF(originalRelation
							.getRelation("Universal"));
					relBCNF.printRelations();
					break;
				} else {
					System.out
							.println("Sorry, that relation has an MVD, you may only select 4NF (#3)");
					break;
				}
			case 3:
				rel4nf = am.build4NF(originalRelation);
				rel4nf.printRelations();
				break;
			case 4:
				originalRelation = new RelationHolder("Original Relation");
				rel3nf = new RelationHolder(
						"3NF - Lossless Decompositions and Dependency Preservation");
				relBCNF = new RelationHolder(
						"BCNF - Lossless Join Property Preserved");
				rel4nf = new RelationHolder(
						"4NF - Lossless Join Property Preserved");

				beforeInputDialog();
				getInput(originalRelation, am, sc);
				afterInputDialog();
				break;
			}
		} while (choice != 0);
	}

	/**
	 * 
	 */
	private static void beforeInputDialog() {
		System.out.println("Enter a relation in this format: ");
		System.out.println("#of FDs followed by each FD on a seperate line, "
				+ "with a \">\" separating each side of the FD ");
		System.out
				.println("Use a semicolon \";\" to represent a multivalued dependency.");
		System.out.println("ex:\n4");
		System.out.println("AB>C\nC>D\nD>EA\nEA;C");
	}

	/**
	 * 
	 */
	private static void afterInputDialog() {
		System.out.println("Please type a number.");
		System.out
				.println("1 - 3NF with dependency preservation and lossless join properties preserved");
		System.out.println("2 - BCNF with lossless join property preserved");
		System.out.println("3 - 4NF with lossless join property preserved");
		System.out
				.println("4 - Start over! (must be done after each calculation)");
		System.out.println("0 - exit");
	}

	/**
	 * 
	 */
	private static void getInput(RelationHolder originalRelation,
			AlgorithmManager am, Scanner sc) {

		int numOfFDs = sc.nextInt();

		Relation r = new Relation();
		r.setRelationName("Universal Relation");

		for (int i = 0; i <= numOfFDs; i++) {
			String s = sc.nextLine();
			Set alLeft = new HashSet();
			Set alRight = new HashSet();
			boolean onLeft = true;

			FunctionalDependency fd = new FunctionalDependency();

			for (int j = 0; j < s.length(); j++) {

				char n = s.charAt(j);
				// move to adding attributes to alRight
				if (n == '>') {
					onLeft = false;
					j++;
					n = s.charAt(j);
				} else if (n == ';') {
					onLeft = false;
					j++;
					try {
						n = s.charAt(j);
					} catch (StringIndexOutOfBoundsException e) {
						break;
					}
					fd.setMultiVal(true);
				}

				if (onLeft) {
					// Attribute att = new Attribute(n);
					String m = "" + n;
					alLeft.add(m);
				} else {
					// Attribute att = new Attribute(n);
					String m = "" + n;
					alRight.add(m);
				}
			}

			// puts the FD into the relation hash map
			fd.setKey(alLeft);
			fd.setValue(alRight);
			// fd.fd.put(alLeft, alRight);
			if (!fd.getKey().isEmpty())
				r.getRelation().add(fd);
		} // end building universal relation

		originalRelation.getRelationHolder().put("Universal", r);

		// Build the cannonical form and minimal set of the universal relation
		// (might as well, right?)
		originalRelation.getRelationHolder()
				.put("CanonicalForm",
						am.buildCanonicalForm(originalRelation
								.getRelation("Universal")));
		originalRelation.getRelationHolder().put(
				"MinimalSet",
				am.buildMinimalSet(originalRelation
						.getRelation("CanonicalForm")));
		originalRelation.getRelation("MinimalSet").generateSetOfAllAttribs();
		originalRelation.getRelation("MinimalSet").setKey(
				am.generatePrimaryKey(originalRelation
						.getRelation("MinimalSet")));
	}
}
